package com.atguigu.lease.web.admin.service.impl;

import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.model.entity.*;
import com.atguigu.lease.model.enums.ItemType;
import com.atguigu.lease.model.enums.ReleaseStatus;
import com.atguigu.lease.web.admin.mapper.ApartmentInfoMapper;
import com.atguigu.lease.web.admin.service.*;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentDetailVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentItemVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentQueryVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentSubmitVo;
import com.atguigu.lease.web.admin.vo.fee.FeeValueVo;
import com.atguigu.lease.web.admin.vo.graph.GraphVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author liubo
 * @description 针对表【apartment_info(公寓信息表)】的数据库操作Service实现
 * @createDate 2023-07-24 15:48:00
 */
@Service
@Transactional
public class ApartmentInfoServiceImpl extends ServiceImpl<ApartmentInfoMapper, ApartmentInfo>
        implements ApartmentInfoService {

    @Autowired
    private ApartmentFacilityService apartmentFacilityService ;

    @Autowired
    private ApartmentFeeValueService apartmentFeeValueService;

    @Autowired
    private ApartmentLabelService apartmentLabelService;

    @Autowired
    private GraphInfoService graphInfoService;

    @Autowired
    private ApartmentInfoMapper apartmentInfoMapper;

    @Autowired
    private LabelInfoService labelInfoService ;

    @Autowired
    private FeeValueService feeValueService;

    @Autowired
    private RoomInfoService roomInfoService ;


    @Override
    public void saveOrUpdateApartment(ApartmentSubmitVo apartmentSubmitVo) {

        Long apartmentId0 = apartmentSubmitVo.getId();
        boolean updateFlag = apartmentId0!=null && apartmentId0!=0;

        //1.保存或更新 ApartmentInfo自身的信息 (insert或update apartmentInfo表)
        super.saveOrUpdate(apartmentSubmitVo);

        //2.如果是更新，则需要先删除掉之前的关系信息
        if(updateFlag){
            //2-1.删除和配套之间的关系
            /*
            apartmentSubmitVo.getFacilityInfoIds().forEach(facilityId->{
                apartmentFacilityService.remove(new LambdaQueryWrapper<ApartmentFacility>()
                        .eq(ApartmentFacility::getFacilityId, facilityId)
                        .eq(ApartmentFacility::getApartmentId,apartmentId));
            });
            */
            apartmentFacilityService.remove(new LambdaQueryWrapper<ApartmentFacility>().eq(ApartmentFacility::getApartmentId,apartmentId0));
            //2-2.删除和标签之间的关系
            apartmentLabelService.remove(new LambdaQueryWrapper<ApartmentLabel>().eq(ApartmentLabel::getApartmentId,apartmentId0));
            //2-3.删除和杂费之间的关系
            apartmentFeeValueService.remove(new LambdaQueryWrapper<ApartmentFeeValue>().eq(ApartmentFeeValue::getApartmentId,apartmentId0));
            //2-4.删除之前的图片
            graphInfoService.remove(new LambdaQueryWrapper<GraphInfo>().eq(GraphInfo::getItemId,apartmentId0).eq(GraphInfo::getItemType,ItemType.APARTMENT));
        }

        //3.保存公寓的关系信息(和配套的关系、和杂费的关系、和标签的关系、和图片的关系)
        //3-1.保存和配套的关系信息
        //apartmentSubmitVo.getFacilityInfoIds() 得到的是一个List<Long>集合，这个集合里面保存的是facilityId
        //.stream()  变成流，因为我们要进行流式计算
        //.map()     将stream中的每一个元素做一个动作，做完动作之后返回的一个一个的对象，形成一个stream流

        //forEach中是方法引用： 实例对象名称::实例方法名称
        //使用方法引用的语法前提是：  forEach这个方法的输入参数正好是  方法引用的那个方法的输入参数
        Long apartmentId = apartmentSubmitVo.getId();
        apartmentSubmitVo.getFacilityInfoIds().stream().map(facilityId->new ApartmentFacility(apartmentId,facilityId))
                .forEach(apartmentFacilityService::saveOrUpdate);

        //3-2. 保存和杂费的关系信息
        apartmentSubmitVo.getFeeValueIds().stream().map(feeValueId->new ApartmentFeeValue(apartmentId,feeValueId))
                .forEach(apartmentFeeValueService::saveOrUpdate);

        //3-3. 保存和标签的关系信息
        apartmentSubmitVo.getLabelIds().stream().map(labelId->ApartmentLabel.builder().apartmentId(apartmentId).labelId(labelId).build())
                .forEach(apartmentLabelService::saveOrUpdate);

        //3-4. 保存图片信息
        /*
        List<GraphInfo> graphInfoList = new ArrayList<>();
        apartmentSubmitVo.getGraphVoList().forEach(graphVo -> {
            GraphInfo graphInfo = new GraphInfo();
            BeanUtils.copyProperties(graphVo,graphInfo);
            graphInfo.setItemType(ItemType.APARTMENT);
            graphInfo.setItemId(apartmentId);

            graphInfoList.add(graphInfo);
        });
        graphInfoService.saveOrUpdateBatch(graphInfoList);
        */

        /*
        graphInfoService.saveOrUpdateBatch(
            apartmentSubmitVo.getGraphVoList().stream().map(graphVo -> {
                GraphInfo graphInfo = new GraphInfo();
                BeanUtils.copyProperties(graphVo,graphInfo);
                graphInfo.setItemType(ItemType.APARTMENT);
                graphInfo.setItemId(apartmentId);
                return graphInfo;
            }).collect(Collectors.toList())
        );
        */
        graphInfoService.saveOrUpdateBatch(
                apartmentSubmitVo.getGraphVoList().stream().map(graphVo ->
                    GraphInfo.builder()
                            .name(graphVo.getName())
                            .url(graphVo.getUrl())
                            .itemType(ItemType.APARTMENT)
                            .itemId(apartmentId).build()
                ).collect(Collectors.toList())
        );

    }

    @Override
    public void pageApartmentItemByQuery(IPage<ApartmentItemVo> page, ApartmentQueryVo queryVo) {
        apartmentInfoMapper.pageApartmentItemByQuery(page,queryVo);
    }

    @Override
    public ApartmentDetailVo getApartmentDetail(Long apartmentId) {
        //业务方法：获取公寓详情，应该包含如下五个动作：
        //1.获取公寓基本信息
        ApartmentInfo apartmentInfo = getById(apartmentId);
        if(apartmentInfo!=null) {
            //2.获取公寓的配套信息
            List<FacilityInfo> facilityList = apartmentFacilityService.getApartmentFacilityListByApartmentId(apartmentId);
            //3.获取公寓的标签信息
            List<LabelInfo> labelInfoList = labelInfoService.getLabelInfoListByApartmentId(apartmentId);
            //4.获取公寓的杂费信息
            List<FeeValueVo> feeValueList = feeValueService.getFeeValueListByApartmentId(apartmentId);
            //5.获取公寓的图片信息
            List<GraphInfo> graphInfoList = graphInfoService.list(new LambdaQueryWrapper<GraphInfo>().eq(GraphInfo::getItemType, ItemType.APARTMENT).eq(GraphInfo::getItemId, apartmentId));

            ApartmentDetailVo apartmentDetailVo = new ApartmentDetailVo();
            BeanUtils.copyProperties(apartmentInfo, apartmentDetailVo);
            apartmentDetailVo.setFacilityInfoList(facilityList);
            apartmentDetailVo.setLabelInfoList(labelInfoList);
            apartmentDetailVo.setFeeValueVoList(feeValueList);
            apartmentDetailVo.setGraphVoList(graphInfoList.stream().map(graphInfo -> GraphVo.builder().name(graphInfo.getName()).url(graphInfo.getUrl()).build()).collect(Collectors.toList()));

            return apartmentDetailVo;
        }
        return null ;
    }

    @Override
    public void removeApartmentById(Long id) {

        //如果待删除的公寓有房间信息，则不允许删除，直接给前端报207错误
        if(roomInfoService.count(new LambdaQueryWrapper<RoomInfo>().eq(RoomInfo::getApartmentId,id))>0){
            //此处抛异常会被全局异常处理器捕获
            throw new LeaseException(ResultCodeEnum.DELETE_ERROR);
        }

        //删除公寓本身的信息
        super.removeById(id);

        //删除这个公寓关联的信息:配套、标签、杂费、图片
        //1.配套(删除的是中间关系表中的记录。不是删除配套表中的信息。)
        apartmentFacilityService.remove(new LambdaQueryWrapper<ApartmentFacility>().eq(ApartmentFacility::getApartmentId,id));
        //2.标签
        apartmentLabelService.remove(new LambdaQueryWrapper<ApartmentLabel>().eq(ApartmentLabel::getApartmentId,id));
        //3.杂费
        apartmentFeeValueService.remove(new LambdaQueryWrapper<ApartmentFeeValue>().eq(ApartmentFeeValue::getApartmentId,id));
        //4.图片(删除的是图片表)
        graphInfoService.remove(new LambdaQueryWrapper<GraphInfo>().eq(GraphInfo::getItemType,ItemType.APARTMENT).eq(GraphInfo::getItemId,id)) ;
    }

    @Override
    public void updateStatus(Long id, ReleaseStatus status) {
        super.update(new LambdaUpdateWrapper<ApartmentInfo>().eq(ApartmentInfo::getId,id).set(ApartmentInfo::getIsRelease,status));
    }
}




